package com.tetris;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.*;
import javax.swing.border.LineBorder;

import com.tetris.common.FileUtil;

import sun.audio.AudioPlayer;
import sun.audio.AudioStream;

public class Tetris extends JFrame implements KeyListener,ActionListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	Timer t = new Timer(300,this);   //下落速度
	Node[] node = new Node[4];		//存下落方块的数组
	int which =0;		//标记下落中的数组是哪一种？
	boolean[][] has = new boolean[20][10];//标记每一个是否有方块
	JLabel[][] label = new JLabel[20][10];//所有的方块
	ArrayList<Integer> list = new ArrayList<Integer>();//此链表用来记录满格的行数
	int[] num = new int[20];//用来记录每行的方块数，以便满十的时候消行
	int scores = 0;   //分数
	private JLabel lbScores;    //用来显示分数的标签
	public static void main(String[] args) {
		new Tetris();
	}
	
	//构造，对某些东西进行初始化
	Tetris(){
		
		//对frame进行布局
		this.setLayout(new FlowLayout());
		JPanel pnShow = new JPanel();
		JPanel pnMessage = new JPanel();
		this.getContentPane().add(pnShow);
		this.getContentPane().add(pnMessage);
		this.addKeyListener(this);
		this.setBounds(200, 100, 400, 550);
		//俄罗斯方块的面板
		pnShow.setLayout(new GridLayout(20,10));//将其设置为20行，10列
		for(int i=0;i<20;i++){					//向中添加label标签
			for(int j=0;j<10;j++){
				label[i][j] = new JLabel();
				pnShow.add(label[i][j]);
			}
		}
		pnShow.setSize(250, 500);
		pnShow.setBorder(new LineBorder(Color.red));
		
		lbScores = new JLabel();
		lbScores.setText("分数："+scores);
		JTextArea area = new JTextArea();
		area.setEnabled(false);
		area.append("  开始，暂停： 空格\n  新游戏：N\n");
		pnMessage.setLayout(new BorderLayout());
		pnMessage.add(lbScores, BorderLayout.NORTH);
		pnMessage.add(area, BorderLayout.CENTER);
		reset();
		
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		t.start();
	}
	public void reset(){
		which = Math.abs(new Random().nextInt(6));
		if(which==0){
			node[0] = new Node(0,5,0);
			node[1] = new Node(0,6,0);
			node[2] = new Node(1,6,0);
			node[3] = new Node(1,7,0);
		}else if(which==1){
			node[0] = new Node(0,4,1);
			node[1] = new Node(0,5,1);
			node[2] = new Node(0,6,1);
			node[3] = new Node(0,7,1);
		}else if(which==2){
			node[0] = new Node(1,5,2);
			node[1] = new Node(1,6,2);
			node[2] = new Node(0,6,2);
			node[3] = new Node(0,7,2);
		}else if(which==3){
			node[0] = new Node(0,4,0);
			node[1] = new Node(1,4,0);
			node[2] = new Node(0,5,0);
			node[3] = new Node(1,5,0);
		}else if(which==4){
			node[0] = new Node(0,4,1);
			node[1] = new Node(0,5,1);
			node[2] = new Node(0,6,1);
			node[3] = new Node(1,5,1);
		}else if(which==5){
			node[0] = new Node(0,4,2);
			node[1] = new Node(0,5,2);
			node[2] = new Node(0,6,2);
			node[3] = new Node(1,6,2);
		}
		setIcon();
		if(has[node[0].x][node[0].y]||has[node[1].x][node[1].y]
		   ||has[node[2].x][node[2].y]||has[node[3].x][node[3].y]){
			t.stop();
			JOptionPane.showMessageDialog(null, "你输了!");
		}
	}
	
	
	public void setNull(){//设置为空
		for(int i=0;i<4;i++)
			label[node[i].x][node[i].y].setIcon(null);
	}
	public void setIcon(){//设置为方块
		for(int i=0;i<4;i++)
			label[node[i].x][node[i].y].setIcon(FileUtil.getIcon(node[i].c));
	}
	
	//键盘监听器
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==32){
			if(t.isRunning())
				t.stop();
			else
				t.start();
		}
		switch(e.getKeyCode()){
		case 37: moveLeft();break;
		case 38: change();  break;
		case 39: moveRight();break;
		case 40: moveDown();break;
		}
	}

	public void keyReleased(KeyEvent e) {
	}
	public void keyTyped(KeyEvent e) {
	}
	public void actionPerformed(ActionEvent e) {
		moveDown();
	}
	
	private void change() {
		if(which==3)
			return;
		if(which==0){//z状
			setNull();
			if(node[0].y==node[3].y&&node[3].y<8&&!has[node[3].x-1][node[3].y+2]){
				node[0].x--;
				node[3].y += 2;
				node[3].x--;
			}else if(node[3].x<17&&!has[node[3].x+1][node[3].y-2]){
				node[0].x++;
				node[3].y = node[0].y;
				node[3].x = node[0].x+1;
			}
			setIcon();
		}else if(which==1){
			if(node[0].x==node[1].x){//如果方块为横向排列的
				if(!has[node[1].x+1][node[1].y]&&!has[node[1].x+2][node[1].y]&&!has[node[1].x+3][node[1].y]){
					setNull();
					node[0].x = node[1].x;
					node[0].y = node[1].y;
					node[2].y = node[1].y;
					node[3].y = node[1].y;
					node[1].x = node[0].x+1;
					node[2].x = node[0].x+2;
					node[3].x = node[0].x+3;
					setIcon();
				}
			}else if(node[0].y<7){//方块为竖直排列的
				if(!has[node[0].x][node[0].y-1]&&!has[node[0].x][node[0].y+1]&&!has[node[0].x][node[0].y+2]){
					setNull();
					node[0].y--;
					node[1].x = node[0].x;
					node[2].x = node[0].x;
					node[3].x = node[0].x;
					node[1].y = node[0].y+1;
					node[2].y = node[0].y+2;
					node[3].y = node[0].y+3;
					setIcon();
				}
			}
		}else if(which==2){
			if(node[2].x==node[3].x&&node[3].x<18&&!has[node[2].x][node[2].y-1]&&!has[node[3].x+2][node[3].y-1]){
				//3号位往左移动一位，四号位往左移动一位，往下移动两位
				setNull();
				node[2].y--;
				node[3].x += 2;
				node[3].y -= 1;
				setIcon();
			}else if(node[3].y<8&&!has[node[3].x-2][node[3].y+1]){
				
				//3号位往左移动一位，四号位往左移动一位，往下移动两位
				setNull();
				node[2].y++;
				node[3].x -= 2;
				node[3].y++;
				setIcon();
			}
		}else if(which==4){//当方块为凸形式
			if(node[0].x==node[1].x){//一号 二号 位同行    
				//第一种情况-->二况     三号位下移一位，一号位下移两位，右移一位
				if(node[0].x>17||has[node[0].x+2][node[0].y+1]||has[node[2].x+1][node[2].y])
					return;
				setNull();
				node[0].x += 2;
				node[0].y++;
				node[2].x++;
				setIcon();
				
			}else if(node[0].y==node[1].y){//一二号位同列     
				//第二种情况-->三况  一号位左移一位，上移一位
				if(node[0].y==0||has[node[0].x-1][node[0].y-1])
					return;
				setNull();
				node[0].x--;
				node[0].y--;
				setIcon();
				
			}else if(node[1].y==node[2].y){//二三号位同列     
				//第四种情况-->一况    一号位上移一位，三号位上移两位，右移一位
				if(node[2].y==9||has[node[0].x-1][node[0].y]||has[node[2].x-2][node[2].y+1])
					return;
				setNull();
				node[0].x--;
				node[2].x -= 2;
				node[2].y++;
				setIcon();
			}else {                //第三种情况
				//三况-->四况    三号位 左移下移各一位
				if(node[2].x==19||has[node[2].x+1][node[2].y-1])
					return;
				setNull();
				node[2].x++;
				node[2].y--;
				setIcon();
			}
		}else if(which==5){//当方块为手枪时
			if(node[2].y==node[3].y){//一况-->二况  
				if(node[3].x==19||has[node[1].x+1][node[1].y]||has[node[1].x+2][node[1].y]||has[node[1].x+2][node[1].y-1])
					return;
				setNull();
				node[0].y++;
				node[1].x++;
				node[2].y--;
				node[2].x += 2;
				node[3].x = node[2].x;
				node[3].y -= 2;
				setIcon();
			}else if(node[0].y==node[3].y){//三况-->四况
				if(node[0].x==19||has[node[0].x+1][node[0].y])
					return;
				setNull();
				node[3].y++;
				node[0].x--;
				node[1].y--;
				node[2].x++;
				node[2].y-=2;
				node[0].y++;
				node[1].y++;
				node[2].y++;
				node[3].y++;
				setIcon();
			}else if(node[1].y==node[3].y){//四况-->一况
				if(node[3].y>7||has[node[3].x][node[3].y+1]||has[node[3].x+1][node[3].y+1])
					return;
				setNull();
				node[1].x--;
				node[1].y++;
				node[2].x -=2;
				node[2].y +=2;
				node[3].x++;
				node[3].y++;
				setIcon();
			}else{//二况-->三况
				if(has[node[2].x][node[2].y+1])
					return;
				setNull();
				node[0].x++;
				node[0].y--;
				node[2].x--;
				node[2].y++;
				node[3].x = node[0].x-1;
				node[3].y = node[0].y;
				setIcon();
			}
			
		}
	
		
	}
	//左键触发,当左键触发时调用
	private void moveLeft(){
		//往左移，不触墙，且无障碍物是进入if，左移一位
		if(node[0].y>0&&node[1].y>0&&node[2].y>0&&node[3].y>0&&!has[node[1].x][node[1].y-1]&&!has[node[1].x][node[1].y-1]&&
				!has[node[2].x][node[2].y-1]&&!has[node[3].x][node[3].y-1]){
			setNull();
			for(int i=0;i<4;i++)
				node[i].y--;
			setIcon();
		}
	
	}
	//右键，当右键触发时调用
	private void moveRight(){
		if(node[2].y<9&&node[3].y<9&&!has[node[1].x][node[1].y+1]&&!has[node[1].x][node[1].y+1]&&
		!has[node[2].x][node[2].y+1]&&!has[node[3].x][node[3].y+1]){//3，4号位小于9，整体就小于9,且2，3，4号位右边都为false
			setNull();
			for(int i=0;i<4;i++)
				node[i].y++;
			setIcon();
		}
	
	}
	//方法判断此时是否撞墙
	private boolean hit(){
		int[] x = new int[4];
		int[] y = new int[4];
		for(int i=0;i<4;i++){
			x[i] = node[i].x;
			y[i] = node[i].y;
		}
		return false;
	}
	//方块向下移动的方法，当timer触发或者下键触发时调用
	private void moveDown() {
		int[] x = new int[4];
		int[] y = new int[4];
		for(int i=0;i<4;i++){
			x[i] = node[i].x;
			y[i] = node[i].y;
		}
		for(int i=0;i<4;i++)
			x[i]++;
		if(x[3]>19||x[1]>19||x[2]>19||x[0]>19||has[x[0]][y[0]]||has[x[1]][y[1]]||has[x[2]][y[2]]||has[x[3]][y[3]]){
			for(int i=0;i<4;i++){
				has[node[i].x][node[i].y] = true;
				num[node[i].x]++;
				if(num[node[i].x]==10)
					list.add(node[i].x);
			}
			if(list.size()!=0){
				for(int i=0;i<list.size();i++)
					sub(list.get(i).intValue());
					list.clear();
			}
			reset();
			return;
		}
		setNull();
		for(int i=0;i<4;i++){
			has[node[i].x][node[i].y] = false;
			label[x[i]][y[i]].setIcon(FileUtil.getIcon(node[i].c));
			node[i].x = x[i];
			node[i].y = y[i];
		}
	}
	
	//消行的方法
	public void sub(int x){
		//播放消行的声音
		try {
			FileInputStream in = new FileInputStream("\\music\\drip.au");
			AudioStream audio = new AudioStream(in);
			AudioPlayer.player.start(audio);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch(IOException eIO){
			eIO.printStackTrace();
		}

		scores+=10;
		lbScores.setText(" 分数："+scores);
		for(int i=x;i>0;i--){
			for(int j=0;j<10;j++){
				label[i][j].setIcon(label[i-1][j].getIcon());
				has[i][j] = has[i-1][j];
			}
			num[i] = num[i-1];
			if(num[i-1]==0)
				break;
		}
		
	}
	
	
}

class Node{
    int x;
	int y;
	int c;
	Node(int x,int y,int c){
		this.x = x;
		this.y = y;
		this.c = c;
	}
}
